import { Stage, Layer, Group, Image, Rect, Path, Line, Text } from "konva";
import scoreUnderline from "@/assets/paper-trace/score-underline.png";
import { loadImage } from "@/utils";

let stage = null;
let imageLayer = null;
let imageGroup = null;
let imageGroupConfig = {};
let mainLayer = null;
let mainGroup = null;
let mainGroupConfig = {};
let wordGroup = null;
let sentenceGroup = null;
let paragraphGroup = null;
let wordList = null;
let sentenceList = null;
let paragraphList = null;

let scale = 1;
let minScale = 1;
let maxScale = 3;
let isDragging = false;
let isPinching = false;
let lastTouchPos = { x: 0, y: 0 };
let lastTouchDistance = 0;
let lastTouchCenter = { x: 0, y: 0 };

const wordRectStrokeWidth = 3;
const underlineStrokeWidth = 3;

function initStage(config) {
    const { container, width, height } = config;

    stage = new Stage({
        container,
        width,
        height,
    });
}

function initImageLayer(groupConfig) {
    imageLayer = new Layer();
    stage.add(imageLayer);

    imageGroup = new Group(groupConfig);
    imageLayer.add(imageGroup);

    imageGroupConfig = groupConfig;
}

function initMainLayer(groupConfig) {
    mainLayer = new Layer();
    stage.add(mainLayer);

    mainGroup = new Group(groupConfig);
    mainLayer.add(mainGroup);

    mainGroupConfig = groupConfig;
}

function renderBgImages(list) {
    for (let i = 0; i < list.length; i++) {
        const { img, x, y, width, height } = list[i];
        const image = new Image({
            x,
            y,
            width,
            height,
            image: img,
        });
        imageGroup.add(image);
    }
}

function renderMask(config) {
    const mask = new Rect({
        x: 0,
        y: 0,
        width: imageLayer.width(),
        height: imageGroup.height(),
        fill: "rgba(0,0,0,0.2)",
        ...config,
    });
    mainGroup.add(mask);
}

function renderWords(list) {
    if (!wordGroup) {
        wordGroup = new Group({ name: "wordGroup" });
        mainGroup.add(wordGroup);
    }
    wordList = list;
    for (let i = 0; i < list.length; i++) {
        const item = list[i];
        const { isHighlight, cooridates } = item;
        const group = new Group({
            name: "wordGroupItem",
            index: i,
        });
        for (let j = 0; j < cooridates.length; j++) {
            const cooridate = cooridates[j];
            const { x, y, width, height } = cooridate;
            const rectInteraction = createInteractionRect({
                ...cooridate,
                opacity: isHighlight ? 1 : 0,
            });
            const rectFrame = new Rect({
                x,
                y,
                width,
                height,
                stroke: "#FFB10B",
                strokeWidth: wordRectStrokeWidth,
            });
            group.add(rectInteraction);
            group.add(rectFrame);
        }
        wordGroup.add(group);
    }
}

function renderSentences(list) {
    if (!sentenceGroup) {
        sentenceGroup = new Group({ name: "sentenceGroup" });
        mainGroup.add(sentenceGroup);
    }
    sentenceList = list;
    for (let i = 0; i < list.length; i++) {
        const item = list[i];
        const { isHighlight, cooridates } = item;
        const group = new Group({
            name: "sentenceGroupItem",
            index: i,
        });

        const interactionGroup = new Group({
            opacity: isHighlight ? 1 : 0,
        }); // 高亮交互组
        const orderNumberGroup = new Group({}); // 序号组
        const waveLineGroup = new Group(); // 波浪线组

        for (let j = 0; j < cooridates.length; j++) {
            const cooridate = cooridates[j];
            const { x, y, width, height } = cooridate;
            const rectInteraction = createInteractionRect(cooridate);
            interactionGroup.add(rectInteraction);

            const wavePath = new Path(
                createWaveLineConfig({
                    ...cooridate,
                    strokeWidth: underlineStrokeWidth,
                })
            );
            waveLineGroup.add(wavePath);
        }

        group.add(interactionGroup);
        group.add(orderNumberGroup);
        group.add(waveLineGroup);
        sentenceGroup.add(group);
    }
}

function renderParagraphs(list) {
    if (!paragraphGroup) {
        paragraphGroup = new Group({ name: "paragraphGroup" });
        mainGroup.add(paragraphGroup);
    }
    paragraphList = list;
    for (let i = 0; i < list.length; i++) {
        const item = list[i];
        const { isHighlight, cooridates } = item;
        const group = new Group({
            name: "paragraphGroupItem",
            index: i,
        });

        const interactionGroup = new Group({
            opacity: isHighlight ? 1 : 0,
        }); // 高亮交互组
        const underLineGroup = new Group();

        for (let j = 0; j < cooridates.length; j++) {
            const cooridate = cooridates[j];
            const { x, y, width, height } = cooridate;
            const rectInteraction = createInteractionRect(cooridate);
            interactionGroup.add(rectInteraction);

            const underLine = new Line(createUnderLineConfig(cooridate));
            underLineGroup.add(underLine);

            group.add(interactionGroup);
            group.add(underLineGroup);
            paragraphGroup.add(group);
        }
    }
}

async function renderScore({ group: groupConfig, text: textConfig, score }) {
    const scoreGroup = new Group({ ...groupConfig, name: "scoreGroup" });
    const scoreText = new Text({ ...textConfig, text: score });

    const scoreUnderlineImage = await loadImage(scoreUnderline);
    const imageConfig = calUnderlineImageConfig(scoreText, scoreUnderlineImage);
    const image = new Image(imageConfig);

    scoreGroup.add(scoreText);
    scoreGroup.add(image);
    mainGroup.add(scoreGroup);
}

function calUnderlineImageConfig(scoreText, img) {
    const scale = 1.8;
    const scoreTextWidth = scoreText.width();
    const scoreTextHeight = scoreText.height();
    const underlineWidth = scoreTextWidth * scale;
    const underlineHeight = underlineWidth * (img.height / img.width);
    const imageConfig = {
        image: img,
        x: -scoreTextWidth / scale + 10,
        y: scoreTextHeight,
        width: underlineWidth,
        height: underlineHeight,
    };
    return imageConfig;
}

function bindMarkEvent() {
    bindTapClickEvent(wordGroup, wordList, renderWords);
    bindTapClickEvent(sentenceGroup, sentenceList, renderSentences);
    bindTapClickEvent(paragraphGroup, paragraphList, renderParagraphs);
}

function bindTapClickEvent(node, list, renderFunc) {
    node.on("tap click", (e) => {
        const groupItem = findUpwardNode(e.target, `${node.name()}Item`);
        if (groupItem) {
            const { index } = groupItem;
            for (let i = 0; i < list.length; i++) {
                list[i].isHighlight = false;
                if (i === index) {
                    list[i].isHighlight = true;
                }
            }
            node.destroyChildren();
            renderFunc && renderFunc(list);
        }
    });
}

// 向上级寻找对应 name 的节点
function findUpwardNode(node, name) {
    if (node.name() === name) {
        return node;
    }
    if (node.parent) {
        return findUpwardNode(node.parent, name);
    }
    return null;
}
// 创建高亮交互区域
function createInteractionRect({ x, y, width, height, opacity = 1 }) {
    return new Rect({
        x,
        y,
        width,
        height,
        fill: "rgba(0,0,0,1)",
        globalCompositeOperation: "destination-out",
        opacity,
    });
}
// 创建波浪线
function createWaveLineConfig({
    x: startX,
    y: startY,
    width,
    height,
    strokeWidth,
}) {
    // 定义波浪路径参数
    const amplitude = 1.5; // 振幅：波峰的高度
    const frequency = 0.35; // 频率：波的密度（数值越大，波越密集）
    let pathData = "";

    for (let x = startX; x <= startX + width; x++) {
        // 控制路径点的密度
        const y = amplitude * Math.sin(x * frequency);
        const relX = x;
        const relY = startY + y + height + 2; // 2 为波浪线的偏移量
        pathData += x === 0 ? `M ${relX},${relY}` : ` L ${relX},${relY}`;
    }

    return {
        data: pathData,
        stroke: "#23E067", // 绿色
        strokeWidth,
        lineCap: "round", // 圆角端点
    };
}
// 创建下划线
function createUnderLineConfig({ x, y, width, height, strokeWidth }) {
    const deviation = 3; // 偏差
    const endX = x + width;
    const endY = y + height + deviation;

    return {
        points: [x, endY, endX, endY],
        stroke: "#71F0FF",
        strokeWidth,
    };
}

function bindDragAndScaleEvent() {
    stage.on("touchstart", handleTouchstart);
    stage.on("touchmove", handleTouchmove);
    stage.on("touchend", handleTouchend);
    stage.on("touchcancel", handleTouchend);
}
function unBindDragAndScaleEvent() {
    stage.off("touchstart", handleTouchstart);
    stage.off("touchmove", handleTouchmove);
    stage.off("touchend", handleTouchend);
    stage.off("touchcancel", handleTouchend);
}

function handleTouchstart(e) {
    e.evt.preventDefault(); // 阻止默认行为

    const touches = e.evt.touches;
    if (touches.length === 1) {
        // 单指触摸 - 准备拖动
        isDragging = true;
        isPinching = false;

        // 记录触摸起始位置
        lastTouchPos = {
            x: touches[0].clientX,
            y: touches[0].clientY,
        };
    } else if (touches.length === 2) {
        // 双指触摸 - 准备缩放
        isPinching = true;
        isDragging = false;

        // 计算两指间的距离和中心点
        const touch1 = touches[0];
        const touch2 = touches[1];

        lastTouchCenter = {
            x: (touch1.clientX + touch2.clientX) / 2,
            y: (touch1.clientY + touch2.clientY) / 2,
        };

        lastTouchDistance = Math.sqrt(
            Math.pow(touch2.clientX - touch1.clientX, 2) +
                Math.pow(touch2.clientY - touch1.clientY, 2)
        );
    }
}

function handleTouchmove(e) {
    e.evt.preventDefault(); // 阻止默认行为

    const touches = e.evt.touches;
    if (touches.length === 1 && isDragging) {
        // 单指触摸移动 - 处理拖动
        const currentPos = {
            x: touches[0].clientX,
            y: touches[0].clientY,
        };

        // 计算移动距离
        const dx = currentPos.x - lastTouchPos.x;
        const dy = currentPos.y - lastTouchPos.y;

        const tox = imageGroup.x() + dx;
        const toy = imageGroup.y() + dy;
        // 应用移动
        imageGroup.position({
            x: tox,
            y: toy,
        });

        // 同步遮罩的移动
        mainGroup.position({
            x: tox,
            y: toy,
        });

        // 更新上一次触摸位置
        lastTouchPos = currentPos;

        // 应用边界限制
        limitPosition();
        imageLayer.batchDraw();
        mainLayer.batchDraw();
    } else if (touches.length === 2 && isPinching) {
        // 双指触摸移动 - 处理缩放
        const touch1 = touches[0];
        const touch2 = touches[1];

        // 计算新的中心点和距离
        const currentCenter = {
            x: (touch1.clientX + touch2.clientX) / 2,
            y: (touch1.clientY + touch2.clientY) / 2,
        };

        const currentDistance = Math.sqrt(
            Math.pow(touch2.clientX - touch1.clientX, 2) +
                Math.pow(touch2.clientY - touch1.clientY, 2)
        );

        if (lastTouchDistance > 0) {
            // 计算缩放因子
            const scaleFactor = currentDistance / lastTouchDistance;

            // 计算新的缩放比例
            const newScale = Math.max(
                minScale,
                Math.min(maxScale, scale * scaleFactor)
            );

            if (newScale !== scale) {
                // 计算缩放中心点在图片组上的相对位置
                const centerPointOnGroup = {
                    x: (lastTouchCenter.x - imageGroup.x()) / scale,
                    y: (lastTouchCenter.y - imageGroup.y()) / scale,
                };

                // 应用新的缩放比例
                imageGroup.scale({ x: newScale, y: newScale });
                mainGroup.scale({ x: newScale, y: newScale });

                // 调整位置，使缩放中心点保持在双指中心
                const posX = currentCenter.x - centerPointOnGroup.x * newScale;
                const posY = currentCenter.y - centerPointOnGroup.y * newScale;
                imageGroup.position({
                    x: posX,
                    y: posY,
                });
                mainGroup.position({
                    x: posX,
                    y: posY,
                });

                scale = newScale;
            }

            // 处理平移
            const dx = currentCenter.x - lastTouchCenter.x;
            const dy = currentCenter.y - lastTouchCenter.y;

            if (dx !== 0 || dy !== 0) {
                const tx = imageGroup.x() + dx;
                const ty = imageGroup.y() + dy;
                imageGroup.position({
                    x: tx,
                    y: ty,
                });
                // 同步遮罩的平移
                mainGroup.position({
                    x: tx,
                    y: ty,
                });
            }

            // 更新上一次的中心点和距离
            lastTouchCenter = currentCenter;
            lastTouchDistance = currentDistance;

            // 应用边界限制
            limitPosition();
            imageLayer.batchDraw();
            mainLayer.batchDraw();
        }
    }
}
// TODO: 有些逻辑是多余的
function handleTouchend(e) {
    const touches = e.evt.touches;
    if (touches.length === 1) {
        // 从双指变为单指
        isPinching = false;
        isDragging = true;

        // 记录新的触摸位置
        lastTouchPos = {
            x: touches[0].clientX,
            y: touches[0].clientY,
        };

        // 应用边界限制
        limitPosition();
        imageLayer.batchDraw();
        mainLayer.batchDraw();
    } else {
        isPinching = false;
        isDragging = false;
        lastTouchCenter = { x: 0, y: 0 };
        lastTouchDistance = 0;
    }
}

function limitPosition() {
    const groupWidth = imageGroup.width() * scale;
    const groupHeight = imageGroup.height() * scale;
    const stageWidth = stage.width();
    const stageHeight = stage.height();

    let x = imageGroup.x();
    let y = imageGroup.y();

    // 水平方向限制
    if (groupWidth <= stageWidth) {
        // 如果图片组宽度小于舞台宽度，则水平居中
        x = (stageWidth - groupWidth) / 2;
    } else {
        // 否则限制在边界内
        const minX = stageWidth - groupWidth;
        const maxX = 0;
        x = Math.max(minX, Math.min(maxX, x));
    }

    // 垂直方向限制
    if (groupHeight <= stageHeight) {
        // 如果图片组高度小于舞台高度，则垂直居中
        y = (stageHeight - groupHeight) / 2;
    } else {
        // 否则限制在边界内
        const minY = stageHeight - groupHeight;
        const maxY = 0;
        y = Math.max(minY, Math.min(maxY, y));
    }

    // 应用新位置
    imageGroup.position({ x, y });
    mainGroup.position({ x, y });
}

export default {
    initStage,
    initImageLayer,
    initMainLayer,
    renderBgImages,
    renderMask,
    renderWords,
    renderSentences,
    renderParagraphs,
    renderScore,
    bindMarkEvent,
    bindDragAndScaleEvent,
    unBindDragAndScaleEvent,
};
